/*-----------------------------------------------------------------------------
 * @file   app.c
 * @brief  Application for power switch control
 * @author WLH<wanglehui8357@163.com> Copyright (C) 2021~2099.
-----------------------------------------------------------------------------*/
#include "PT32X005.h"
#include <stdbool.h>

//-----------------------------------------------------------------------------
// 按键输入 PC04 (按键中断唤醒)
// 输出控制 PC05 - OUT1  -- 功率电源 (切伞/电调)
//          PA01 - OUT2  --
//          PA02 - OUT3  -- 飞控电源
//          PD03 - OUT4  -- 分支电源(GNSS)
//          PD04 - OUT5  --
//-----------------------------------------------------------------------------
// UART0 用于调试输出/外部通讯 (PD5/PD6)

//-----------------------------------------------------------------------------
#define RCV_BUF_SZ      128

/*-----------------------------------------------------------------------------
 * macros define
-----------------------------------------------------------------------------*/
// 时间戳单位转换为毫秒
#define TICK_TO_MS(a)       ((a)*10u)

// 从指定时间戳计算流逝时间,单位毫秒
#define ELAPSED_MS(a)       TICK_TO_MS(g_system_tick-(a))

// 功率电源开关控制
#define PWR_SUPPLY_ON()     do{ GPIO_SetBits(GPIOC, GPIO_Pin_5);   } while(0)
#define PWR_SUPPLY_OFF()    do{ GPIO_ResetBits(GPIOC, GPIO_Pin_5); } while(0)
// 飞控电源开关控制
#define PWR_AP_ON()         do{ GPIO_SetBits(GPIOA, GPIO_Pin_2);   } while(0)
#define PWR_AP_OFF()        do{ GPIO_ResetBits(GPIOA, GPIO_Pin_2); } while(0)
// 分支电源开关控制
#define PWR_GNSS_ON()       do{ GPIO_SetBits(GPIOD, GPIO_Pin_3);   } while(0)
#define PWR_GNSS_OFF()      do{ GPIO_ResetBits(GPIOD, GPIO_Pin_3); } while(0)

/*-----------------------------------------------------------------------------
 * 系统状态
-----------------------------------------------------------------------------*/
#define SYS_STATE_SLEEP     1   // 睡眠状态
#define SYS_STATE_PWR_OFF   2   // 关机状态
#define SYS_STATE_PWR_ON    3   // 开机状态

/*-----------------------------------------------------------------------------
 * global variates
-----------------------------------------------------------------------------*/
// 系统时间戳
__IO u32 g_system_tick = 0;

/*-----------------------------------------------------------------------------
 * local variates
-----------------------------------------------------------------------------*/
// 按键按下时间戳
static u32 _ts_switch_dw    = 0;
// 状态变更时间戳
static u32 _ts_state_start  = 0;
// 中断触发时间戳
static u32 _ts_exit_start   = 0;
// 是否发生IO中断
static bool _exti_triggered = false;
// 串口数据接收缓冲区
static u8 _rcv_buf[RCV_BUF_SZ];
// 串口数据接收长度
static u8 _rcv_len = 0;
// 系统是否已经全部完成上电
static bool _is_power_on = false;

/*-----------------------------------------------------------------------------
 * local functions
-----------------------------------------------------------------------------*/
static bool command_is_equal(u8 *s1, const char *cmd)
{
    u8 i;
    for(i=0; i<_rcv_len; i++)
    {
        if(s1[i] != (u8)cmd[i]) { return false; }
    }
    return true;
}

/*-----------------------------------------------------------------------------
 * 系统定时器
-----------------------------------------------------------------------------*/
/**
 * @brief 系统定时器初始化
*/
static void sys_timer_init(void)
{
    u32 sys_clk = RCC_GetSYSCLKFreq(); // 获得系统时钟
    if (SysTick_Config(sys_clk / 100)) // 10ms中断一次
    {
        while (1);
    }
}
/**
 * @brief 忙等待延迟函数，须在sys_timer_init后调用
*/
static void delay_ms(const u32 ms)
{
    u32 ts = g_system_tick;
    for(;;)
    {
        if(ELAPSED_MS(ts) >= ms) break;
    }
}

/*-----------------------------------------------------------------------------
 * 电源控制相关
-----------------------------------------------------------------------------*/
/**
 * @brief 配置电源控制引脚
*/
static void power_io_init(void)
{
    GPIO_InitTypeDef io_para;
    io_para.GPIO_Mode = GPIO_OType_PP;
    io_para.GPIO_PuPd = GPIO_PuPd_NOPULL;

    io_para.GPIO_Pin  = GPIO_Pin_5;
    GPIO_Init(GPIOC, &io_para);
    GPIO_ResetBits(GPIOC, GPIO_Pin_5); //PC05

    io_para.GPIO_Pin  = GPIO_Pin_1;
    GPIO_Init(GPIOA, &io_para);
    GPIO_ResetBits(GPIOA, GPIO_Pin_1); //PA01

    io_para.GPIO_Pin  = GPIO_Pin_2;
    GPIO_Init(GPIOA, &io_para);
    GPIO_ResetBits(GPIOA, GPIO_Pin_2); //PA02

    io_para.GPIO_Pin  = GPIO_Pin_3;
    GPIO_Init(GPIOD, &io_para);
    GPIO_ResetBits(GPIOD, GPIO_Pin_3); //PD03

    io_para.GPIO_Pin  = GPIO_Pin_4;
    GPIO_Init(GPIOD, &io_para);
    GPIO_ResetBits(GPIOD, GPIO_Pin_4); //PD04
}

/*-----------------------------------------------------------------------------
 * 用户按键相关
-----------------------------------------------------------------------------*/
/**
 * @brief 配置用户按键的引脚
*/
static void switch_io_init(void)
{
    GPIO_InitTypeDef io_para;
    GPIO_StructInit(&io_para);
    io_para.GPIO_Mode = GPIO_Mode_IN;
    io_para.GPIO_PuPd = GPIO_PuPd_UP;

    io_para.GPIO_Pin  = GPIO_Pin_4;
    GPIO_Init(GPIOC, &io_para);

    // 外部中断触发类型配置
    EXTI_TriTypeConfig(EXTIC, GPIO_Pin_4, EXTI_Trigger_Rising_Falling);
    EXTI_ITConfig(EXTIC, GPIO_Pin_4, ENABLE);  // 外部中断配置

    /* NVIC配置 */
    NVIC_InitTypeDef nvic_para;
    nvic_para.NVIC_IRQChannelCmd = ENABLE;     // 设置是否使能中断
    nvic_para.NVIC_IRQChannelPriority = 0x00;  // 设置中断优先级

    nvic_para.NVIC_IRQChannel = EXTIC_IRQn;    // 设置中断向量号
    NVIC_Init(&nvic_para);                     // 初始化NVIC
}

/*-----------------------------------------------------------------------------
 * 通讯串口相关
-----------------------------------------------------------------------------*/
/**
 * @brief 串口初始化 (115200/8/E/1)
*/
static void app_uart_init(void)
{
    // RX和TX的数字功能复用
    // GPIO_DigRemapConfig(AFIOD, AFIO_Pin_5|AFIO_Pin_6, AFIO_AF_0, ENABLE);
    GPIO_DigRemapConfig(AFIOD, AFIO_Pin_6, AFIO_AF_0, ENABLE);

    UART_InitTypeDef io_para;
    UART_StructInit(&io_para);                    // 使用默认值初始化

    io_para.UART_BaudRate = 115200;               // 设置波特率
    io_para.UART_WordLength = UART_WP_8D;         // 设置数据位
    io_para.UART_StopBits = UART_STOP_1b;         // 设置停止位
    io_para.UART_Parity = UART_PS_EVEN;           // 设置校验位
    io_para.UART_Mode = UART_RE_Enable;           // RX使能
    io_para.UART_LoopBack = UART_LoopBack_Disable;// 环回关闭

    UART_Init(UART0, &io_para);                   // 初始化UART
    UART_Cmd(UART0, ENABLE);                      // 使能UART
}
/**
 * @brief 调试串口字符串打印
*/
static void dbg_print(const char* str)
{
    UART_StringSend(UART0, (u8*)str);
}
/**
 * @brief 轮询读取串口字符串并处理
*/
static void app_uart_poll(void)
{
    // Not Received data
    if(0 == (UART0->SR & UART_SR_RXNE)) return;

    u8 c = UART0->DR;

    // Overflow process
    if (_rcv_len > RCV_BUF_SZ - 8) { _rcv_len = 0; }

    // 过滤无效帧头
    if (_rcv_len == 0 && c != 'A') {               return; }
    if (_rcv_len == 1 && c != 'T') { _rcv_len = 0; return; }
    if (_rcv_len == 2 && c != '+') { _rcv_len = 0; return; }

    _rcv_buf[_rcv_len++] = c;
    if(_rcv_len < 12) { return; }

    // 查找结束字符 '\r\n'
    if (_rcv_buf[_rcv_len-2] == '\r' &&
        _rcv_buf[_rcv_len-1] == '\n')
    {
        // 处理接收到的指令

        // 准备下一包报文处理
        // Debug
        _rcv_buf[_rcv_len++] = '\0';
        UART_StringSend(UART0, _rcv_buf);

        _rcv_len = 0;
    }
}

/*-----------------------------------------------------------------------------
 * 系统状态机设计
-----------------------------------------------------------------------------*/
static void sys_state_set(const u8 state)
{
    // 清理 clicked 状态
    _ts_state_start = g_system_tick;

    if(SYS_STATE_SLEEP == state)
    {
        dbg_print("SLEEP\r\n");

        // 等待打印完毕
        delay_ms(10);

        // 进入系统休眠低功耗模式
        PWR_EnterSTANDBYMode(PWR_STANDBYEntry_WFI);
    }

    if(SYS_STATE_PWR_OFF == state)
    {
        dbg_print("PWR_OFF\r\n");
    }

    if(SYS_STATE_PWR_ON == state)
    {
        dbg_print("PWR_ON\r\n");
    }
}

static void power_control_on(void)
{
    delay_ms(1000);
    PWR_GNSS_ON();
    // delay_ms(50000);
    PWR_AP_ON();
    // delay_ms(1000);
    PWR_SUPPLY_ON();
    // delay_ms(1000);
    _is_power_on = true;
}

static void power_control_off(void)
{
    _is_power_on = false;

    PWR_GNSS_OFF();
    PWR_AP_OFF();
    PWR_SUPPLY_OFF();    
}

static u8  _exti_counter  = 0;
static u32 _exti_first_ts = 0;
static u32 _exti_curr_ts = 0;
/**
 * @brief 外部中断处理函数[前台运行]
 */
static void switch_action_handler(void)
{
    if(!_exti_triggered)
    {
        return;
    }

    if (!_is_power_on)
    {
        power_control_on();
    }
    else
    {
        // 检测是否进行下电逻辑处理
        if (0 == _exti_counter)
        {
            _exti_first_ts = g_system_tick;
        }        

        if (ELAPSED_MS(_exti_curr_ts) >= 50)
        {
            _exti_counter ++;
            _exti_curr_ts = g_system_tick;
        }

        if (ELAPSED_MS(_exti_first_ts) >= 5000)
        {
            _exti_counter = 0;// 处置超时，重置
        }
        
        if (_exti_counter >= 10) // 双边沿触发
        {                        
            power_control_off();
            _exti_counter = 0;
            _exti_curr_ts = 0;
            delay_ms(1000);
            sys_state_set(SYS_STATE_SLEEP);
            power_control_on();
        }
    }

    // 清理中断处理标记
    _exti_triggered = false;
}

/*-----------------------------------------------------------------------------
 * public functions
-----------------------------------------------------------------------------*/
int main (void)
{
    app_uart_init();
    sys_timer_init();
    switch_io_init();
    power_io_init();

    // 上电后,LSI不应该被立刻关闭,应保证上电后至少1ms延时才能够关闭
    delay_ms(10);

    // 关闭LSI
    RCC->LCR=0;

    // 系统状态初始为 Sleep
    sys_state_set(SYS_STATE_SLEEP);

    for(;;)
    {
        //sys_state_run();
        switch_action_handler();
        app_uart_poll();
    }
}

/*-----------------------------------------------------------------------------
 * Override ISR functions
-----------------------------------------------------------------------------*/
void EXTI_PC4_Handler(void)
{
    _exti_triggered = true;
    _ts_exit_start = g_system_tick;
}
